package com.douqu.game.main.msg;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bean.core.buffer.ByteBuffer;
import com.bean.core.util.HttpJsonUtils;
import com.douqu.game.core.controller.PlayerController;
import com.douqu.game.core.database.model.GMLogModel;
import com.douqu.game.core.database.model.GMModel;
import com.douqu.game.core.database.model.PlayerModel;
import com.douqu.game.core.e.E_AuctionStatus;
import com.douqu.game.core.e.E_GMType;
import com.douqu.game.core.e.ReturnMessage;
import com.douqu.game.core.entity.Player;
import com.douqu.game.core.entity.ext.BoonInfo;
import com.douqu.game.core.entity.ext.ChallengeInfo;
import com.douqu.game.core.entity.ext.MailInfo;
import com.douqu.game.core.entity.ext.data.boon.AuctionRewardPlayer;
import com.douqu.game.core.entity.world.WorldAuctionBean;
import com.douqu.game.core.entity.world.map.CityBean;
import com.douqu.game.core.factory.CodeFactory;
import com.douqu.game.core.factory.WorldInfoFactory;
import com.douqu.game.core.netty.NettyConnection;
import com.douqu.game.core.protobuf.SGCommonProto;
import com.douqu.game.core.util.CoreUtils;
import com.douqu.game.core.util.LogUtils;
import com.douqu.game.core.util.StringUtils;
import com.douqu.game.main.GameServer;
import com.douqu.game.main.database.mapper.read.ReadGMLogMapper;
import com.douqu.game.main.server.SpringContext;
import com.douqu.game.main.server.netty.NettyTCPServerHandler;
import com.douqu.game.main.service.GMService;
import com.douqu.game.main.service.PlayerService;
import com.douqu.game.main.util.FixDBUtils;
import io.netty.buffer.ByteBuf;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author: Bean
 * @Description:
 * @Date: 2017-11-08 18:18
 */
public class GMChannel {

	public static void messageChannel(int code, NettyConnection connection, ByteBuf byteBuf)
	{
		LogUtils.info("hello,收到GM消息:" + code + "  源-> " + Integer.toHexString(code));

		GMModel gmModel = (GMModel) connection.getObject();

		ByteBuffer data = CoreUtils.toByteBuffer(byteBuf);

		if (!isCanOption(gmModel, code)) {
			sendError(connection, "你没有权限操作此功能");
			return;
		}


		try {

			int reqCode = Integer.parseInt(Integer.toHexString(code)) / 100;
			if(reqCode == Integer.parseInt(Integer.toHexString(CodeFactory.GM_PLAYER)) / 100)
			{
				LogUtils.info("GM 玩家类消息 -> " + reqCode);

				GMPlayerChannel.messageChannel(code, connection, data);
			}
			else if(reqCode == Integer.parseInt(Integer.toHexString(CodeFactory.GM_SYSTEM)) / 100)
			{
				LogUtils.info("GM 系统类消息 -> " + reqCode);

				GMSystemChannel.messageChannel(code, connection, data);
			}
			else if(reqCode == Integer.parseInt(Integer.toHexString(CodeFactory.GM_DATA)) / 100)
			{
				LogUtils.info("GM 数据类消息 -> " + reqCode);

				GMDataChannel.messageChannel(code, connection, data);
			}
			else
			{
				switch (code) {

					case CodeFactory.GM_ACCOUNT_LIST:
						gmAccountList(connection, code);
						break;
					case CodeFactory.GM_ACCOUNT_ADD:
					case CodeFactory.GM_ACCOUNT_UPDATE:
						gmAccountAddOrUpdate(connection, data, code);
						break;
					case CodeFactory.GM_ACCOUNT_OPTION_LOG:
						gmLogList(connection, data, code);
						break;
					case CodeFactory.GM_ACCOUNT_ONLINE_LIST:
						gmOnlineList(connection, code);
						break;
					case CodeFactory.GM_ACCOUNT_CHAT:
						gmChat(connection, data, code);
						break;

					/** -------------------------------------------- */
					case CodeFactory.GM_MERGE_ALL:
						mergeAll(connection, code);
						break;

					case CodeFactory.GM_MERGE_AUCTION:
						//mergeAuction(connection, code);
						break;
				}
			}

		} catch (Exception e) {
			LogUtils.info("GM操作参数错误 -> " + e.getLocalizedMessage());
			e.printStackTrace();
			sendError(connection, "参数错误!");
		}
	}











	private static void gmOnlineList(NettyConnection connection, int code) {
		List<NettyConnection> gmList = GameServer.getInstance().getWorldManager().getGmList();

		JSONArray jsonArray = new JSONArray();
		JSONObject jsonObject = null;
		GMModel gmModel = null;
		for (NettyConnection gm : gmList) {
			jsonObject = new JSONObject();
			gmModel = (GMModel) gm.getObject();
			jsonObject.put("name", gmModel.getUsername());
			jsonObject.put("type", gmModel.getType());
			jsonArray.add(jsonObject);
		}

		ByteBuffer out = new ByteBuffer();
		out.writeUTF(jsonArray.toJSONString());
		connection.sendMsg(code, out.getBytes());
	}

	private static void gmChat(NettyConnection connection, ByteBuffer data, int code) {
		String content = data.readUTF();
		String target = data.readUTF();
		content = content.replaceAll(" ", "");
		if (CoreUtils.isNullOrEmpty(content) || content.length() > 100) {
			sendError(connection, "内容长度错误(1-100)");
			return;
		}

		List<NettyConnection> gmList = GameServer.getInstance().getWorldManager().getGmList();

		GMModel self = (GMModel) connection.getObject();

		ByteBuffer out = new ByteBuffer();
		out.writeUTF(content);
		out.writeUTF(self.getUsername());
		byte[] sendData = out.getBytes();

		if (CoreUtils.isNullOrEmpty(target)) {
			// 群发
			for (NettyConnection gm : gmList) {
				gm.sendMsg(code, sendData);
			}
		} else {
			GMModel targetGM = null, gmModel = null;
			NettyConnection targetConnection = null;
			for (NettyConnection gm : gmList) {
				gmModel = (GMModel) gm.getObject();
				if (gmModel.getUsername().equals(target)) {
					targetGM = gmModel;
					targetConnection = gm;
					break;
				}
			}

			if (targetGM == null) {
				sendError(connection, "目标GM不在线");
				return;
			}
			if (targetGM.getId() == self.getId()) {
				sendError(connection, "不能对自己发");
				return;
			}

			targetConnection.sendMsg(code, sendData);

			connection.sendMsg(code, sendData);
		}

		String[] strs = content.split(":");
		if("ucc".equals(strs[0]))
		{
			if(strs.length > 2)
			{
				try{
					CityBean cityBean = WorldInfoFactory.getInstance().getWorldMapData().getCity(Integer.parseInt(strs[1]));
					SGCommonProto.E_CAMP_TYPE campType = SGCommonProto.E_CAMP_TYPE.forNumber(Integer.parseInt(strs[2]));
					if(campType != SGCommonProto.E_CAMP_TYPE.CAMP_TYPE_UNKNOWN && cityBean.isPeace() && cityBean.getSpritePlayerList().isEmpty())
					{
						cityBean.camp = campType.getNumber();
						cityBean.initGarrison();
					}
					else
					{
						LogUtils.warn("ucc错误-----------" + content);
					}
				}catch (Exception e){
					LogUtils.warn("ucc错误-----------" + e.getMessage());
				}

			}
		}
	}



	private static void gmLogList(NettyConnection connection, ByteBuffer data, int code) {
		int page = data.readShort();
		int count = data.readByte();
		page = page < 1 ? 1 : page;
		int start = (page - 1) * count;
		count = count < 1 ? 1 : count;

		String keyword = "";
		int startTime = 0;
		int endTime = 0;
		String searchStr = data.available() > 0 ? data.readUTF() : "";
		JSONObject searchJson = null;
		if (searchStr.length() > 0) {
			searchJson = JSONObject.parseObject(searchStr);
			keyword = searchJson.getString("keyword");
			startTime = searchJson.getInteger("startTime");
			endTime = searchJson.getInteger("endTime");
		}

		LogUtils.info("请求参数 -> keyword:" + keyword + " startTime:" + startTime + " endTime:" + endTime);

		ReadGMLogMapper readGMLogMapper = SpringContext.getBean(ReadGMLogMapper.class);
		int totalCount = readGMLogMapper.findCount(keyword, startTime, endTime);

		JSONObject response = new JSONObject();
		if (totalCount > 0) {
			List<GMLogModel> list = readGMLogMapper.findList(keyword, startTime, endTime, start, count);
			JSONArray jsonArray = new JSONArray();
			for (GMLogModel model : list) {
				jsonArray.add(JSONObject.toJSON(model));
			}
			response.put("data", jsonArray.toJSONString());
		}

		response.put("page", page);
		response.put("count", count);
		response.put("totalCount", totalCount);
		response.put("search", searchJson);

		// LogUtils.info("返回数据 -> " + response.toJSONString());

		ByteBuffer out = new ByteBuffer(Integer.MAX_VALUE / 10);
		out.writeUTF(response.toJSONString());
		connection.sendMsg(code, out.getBytes());
	}

	private static void gmAccountAddOrUpdate(NettyConnection connection, ByteBuffer data, int code) {
		GMModel gmModel = (GMModel) connection.getObject();

		String updateData = data.readUTF();
		GMModel reqData = JSON.parseObject(updateData, GMModel.class);
		String username = reqData.getUsername();
		String password = reqData.getPassword();

		if (gmModel.getType() != E_GMType.SUPER.getCode() && !reqData.getUsername().equals(gmModel.getUsername())) {
			sendError(connection, "你没有权限进行此操作!");
			return;
		}
		if (StringUtils.isNullOrEmpty(username) || StringUtils.isNullOrEmpty(password) || reqData.getType() == null
				|| E_GMType.forNumber(reqData.getType()) == null) {
			sendError(connection, "参数错误");
			return;
		}
		username = username.replaceAll(" ", "");
		password = password.replaceAll(" ", "");
		if (username.length() <= 1 || username.length() > 10) {
			sendError(connection, "账号长度错误(1-10)");
			return;
		}
		if (password.length() <= 1 || password.length() > 14) {
			sendError(connection, "密码度错误(1-14)");
			return;
		}
		reqData.setUsername(username);
		reqData.setPassword(password);
//		GMService gmService = SpringContext.getBean(GMService.class);

//		boolean isNew = false;
		if (reqData.getId() == null || reqData.getId() == 0) {
			if (reqData.getType() == E_GMType.SUPER.getCode()) {
				sendError(connection, "不允许添加超级GM");
				return;
			}
//			// 新增
//			GMModel dbModel = gmService.findByName(username);
//			if (dbModel != null) {
//				sendError(connection, "账号已存在");
//				return;
//			}
//
//			reqData.setDel(false);
//			reqData.setDel(false);
//			gmService.create(reqData);
//
//			saveGMLog(connection, null, "添加GM账号:" + reqData.getUsername(), code, username);
//
//			isNew = true;
		} else {
			// 更新 因为GM表在认证服，这里读取不了认证服的数据库，所以以下判断不要了
//			GMModel dbModel = gmService.findById(reqData.getId());
//			if (dbModel == null) {
//				sendError(connection, "编辑的账号不存在");
//				return;
//			}
//
//			if(dbModel.getType() > reqData.getType())
//			{
//				sendError(connection, "不允许改变GM类型");
//				return;
//			}
//
//			if (reqData.getType() == E_GMType.SUPER.getCode() || dbModel.getType() == E_GMType.SUPER.getCode()) {
//				if (reqData.getType() != dbModel.getType()) {
//					sendError(connection, "不允许改变GM类型");
//					return;
//				}
//			}
//
//			if (reqData.isDel() && dbModel.getType() == E_GMType.SUPER.getCode()) {
//				sendError(connection, "不允许禁用超级GM");
//				return;
//			}

			if (reqData.isDel() && reqData.getId() == gmModel.getId()) {
				sendError(connection, "不能禁用自己");
				return;
			}

			if(gmModel.getId() == reqData.getId()) {
				if(gmModel.getType() != reqData.getType()) //不允许改变自己的账号类型
				{
					sendError(connection, "不允许改变账号类型");
					return;
				}
			} else {//不允许改变上级的账号类型
				if(gmModel.getType() > reqData.getType()){
					sendError(connection, "不允许改变账号类型");
					return;
				}
			}

//			if (reqData.isSame(dbModel)) {
//				sendError(connection, "没有任何变化");
//				return;
//			}
//
//			gmService.update(reqData);
//
//			saveGMLog(connection, null, "编辑GM账号:" + reqData.getUsername(), code, username);
		}

		//认证需要返回更新后的列表
		JSONObject resJson = HttpJsonUtils.httpPost(GameServer.getInstance().getAuthServerHost() + "gm/update", JSONObject.parseObject(JSONObject.toJSONString(reqData)));
		if(resJson == null)
		{
			sendError(connection, "请求失败,请检查服务器");
			return;
		}
		if(!resJson.getString("code").equals("0000"))
		{
			sendError(connection, resJson.getString("message"));
			return;
		}

		if(gmModel.getId() == reqData.getId()){
			gmModel.setPassword(reqData.getPassword());
		}

		saveGMLog(connection, null, "添加/编辑GM账号:" + reqData.getUsername(), code, username);

		List<GMModel> list = JSONObject.parseArray(resJson.getString("data"), GMModel.class);
		sendGMList(connection, list);

//		gmAccountList(connection, CodeFactory.GM_ACCOUNT_LIST);
	}

	private static void sendGMList(NettyConnection connection, List<GMModel> list)
	{
		JSONArray jsonArray = new JSONArray();
		JSONObject jsonObject = null;
		GMModel curGM = (GMModel) connection.getObject();
		for (GMModel model : list) {
			jsonObject = new JSONObject();
			jsonObject.put("id", model.getId());
			jsonObject.put("username", model.getUsername());
			if (curGM.getType() == E_GMType.SUPER.getCode() || model.getId() == curGM.getId())
				jsonObject.put("password", model.getPassword());
			else
				jsonObject.put("password", "******");
			jsonObject.put("type", model.getType());
			jsonObject.put("createTime", model.getCreateTime());
			jsonObject.put("isDel", model.isDel());
			jsonArray.add(jsonObject);
		}

		ByteBuffer out = new ByteBuffer();
		out.writeUTF(jsonArray.toJSONString());
		connection.sendMsg(CodeFactory.GM_ACCOUNT_LIST, out.getBytes());
	}

	private static void gmAccountList(NettyConnection connection, int code)
	{
		JSONObject resJson = HttpJsonUtils.httpGet(GameServer.getInstance().getAuthServerHost() + "gm/list");
		if(resJson == null)
		{
			sendError(connection, "请求失败");
			return;
		}
		if(!resJson.getString("code").equals(ReturnMessage.SUCCESS.getCode()))
		{
			sendError(connection, resJson.getString("message"));
			return;
		}

		List<GMModel> list = JSONObject.parseArray(resJson.getString("data"), GMModel.class);
//		GMService gmService = SpringContext.getBean(GMService.class);
//		List<GMModel> list = gmService.findList();
		sendGMList(connection, list);
	}





	public static void sendError(NettyConnection connection, String error) {
		ByteBuffer out = new ByteBuffer();
		out.writeUTF(error);
		connection.sendMsg(CodeFactory.GM_ERROR, out.getBytes());
	}



	public static void savePlayerModel(PlayerModel model) {
		PlayerService playerService = SpringContext.getBean(PlayerService.class);
		playerService.insert(model);
	}

	public static void savePlayer(Player player, boolean updateBase, Class... clsAry) {
		PlayerService playerService = SpringContext.getBean(PlayerService.class);
		playerService.updatePlayers(updateBase, clsAry, player);
	}

	public static void savePlayer(Player player) {
		PlayerService playerService = SpringContext.getBean(PlayerService.class);
		playerService.update(player);
	}

	public static void updatePlayers(List<Player> playerList, boolean updateBase, Class... clsAry) {
		PlayerService playerService = SpringContext.getBean(PlayerService.class);
		playerService.updatePlayers(playerList, updateBase, clsAry);
	}

	public static void saveGMLog(NettyConnection connection, Player player, String content, int type, String value)
	{
		String person = "";
		if(connection != null)
		{
			GMModel gmModel = (GMModel) connection.getObject();
			person = gmModel.getUsername();
		}
		else
		{
			person = "ServerStart";
		}

		GMService gmService = SpringContext.getBean(GMService.class);
		GMLogModel model = new GMLogModel();
		model.setType(type);
		model.setValue(value);
		model.setOptionPerson(person);
		String temp = "";
		if (player != null) {
			model.setPlayerIndex(player.getObjectIndex());
			temp = "目标玩家->" + player.getName() + ",";
		}
		temp += "操作内容->";
		model.setContent(temp + content);
		gmService.createLog(model);
	}





	/************** 合服相关接口 ****************/
	private static void mergeAll(NettyConnection connection, int code) {
		ByteBuffer out = new ByteBuffer();
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.append("开始合服准备...\n");
		stringBuilder.append("开始把所有玩家T下线\n");
		offLineAll();
		stringBuilder.append("所有玩家T下线完成\n");
		// 执行拍卖行
		mergeAuction(connection, code);
		stringBuilder.append("合服准备 -> 处理拍卖行成功\n");
		List<Player> playerList = GameServer.getInstance().getWorldManager().getAllPlayerList();
		//执行福利基金
		mergeBoon(playerList,stringBuilder);
		stringBuilder.append("合服准备 -> 处理基金完成\n");
		//执行争霸赛init
		mergeWorldMap(playerList,stringBuilder);
		stringBuilder.append("合服准备 -> 处理争霸赛完成\n");
		GameServer.getInstance().savePlayerListSync(playerList,false, BoonInfo.class, MailInfo.class,ChallengeInfo.class);
		stringBuilder.append("合服完成 -> 玩家数据成功保存");
		out.writeUTF(stringBuilder.toString());
		connection.sendMsg(code, out.getBytes());

		saveGMLog(connection, null, "合服前处理数据", code, "");
	}

	/**
	 * 将所有玩家T下线
	 */
	private static void offLineAll(){
		NettyTCPServerHandler.mergrReady();
		LogUtils.info("禁止任何玩家登陆 与 请求 success!");
		Map<String,PlayerController> plartIndexMap = GameServer.getInstance().getWorldManager().getAllOnLinePlayerController();
		for (Map.Entry<String,PlayerController> entry:plartIndexMap.entrySet()){
			entry.getValue().serverDestroy();
		}
	}
	//基金
	private static void mergeBoon(List<Player> playerList,StringBuilder stringBuilder){
		for (Player player:playerList) {
			try {
				FixDBUtils.fixMergeArea(player);
			} catch (Exception e) {
				e.printStackTrace();
				LogUtils.errorException(e);
				LogUtils.error("玩家 :" + player.name + " 流水:" + player.objectIndex + "处理基金失败");
				stringBuilder.append("玩家 :" + player.name + " 流水:" + player.objectIndex + "处理基金失败\n");
				continue;
			}
		}
	}

	//争霸赛
	private static void mergeWorldMap(List<Player> playerList,StringBuilder stringBuilder){
		for (Player player:playerList) {
			try {
				player.getWorldMapKillData().init();
			} catch (Exception e) {
				e.printStackTrace();
				LogUtils.errorException(e);
				LogUtils.error("玩家 :" + player.name + " 流水:" + player.objectIndex + "初始化争霸赛失败");
				stringBuilder.append("玩家 :" + player.name + " 流水:" + player.objectIndex + "初始化争霸赛失败\n");
				continue;
			}
		}
	}

	/***
	 * 合服处理拍卖行
	 * @param connection
	 * @param code
	 */
	private static void mergeAuction(NettyConnection connection, int code) {
		// 遍历所有的拍卖是否结束
		WorldAuctionBean auctionBean;
		Map<String, AuctionRewardPlayer> savePlayerMap = new ConcurrentHashMap<>();
//		AuctionConfig auctionConfig = null;
		BoonMsgChannel boonMsgChannel = (BoonMsgChannel) SpringContext.getMessageChannel(BoonMsgChannel.class);
		if (WorldInfoFactory.getInstance().getWorldAuctionData().getAuctionMap().isEmpty()) {
			//sendError(connection, "拍卖行合服已经准备完成");
			return;
		}
		for (Map.Entry<Integer, WorldAuctionBean> entry : WorldInfoFactory.getInstance().getWorldAuctionData()
				.getAuctionMap().entrySet()) {
			auctionBean = entry.getValue();
			// 2.如果没有结束
			if (auctionBean.getState() == E_AuctionStatus.INT_THE_AUCTION.getCode()) {
				// 判断是否到时间
				// 3.获取配置表中的keepTime
//				auctionConfig = WorldAuctionData.getAuctionConfig(auctionBean.getAuctionConfigId());
				// 4.判断是否有人出价
				boonMsgChannel.auctionSuccess(auctionBean,
						!com.douqu.game.core.util.StringUtils.isNullOrEmpty(auctionBean.getCurrentPlayer()), savePlayerMap);
			}
		}

		if (!savePlayerMap.isEmpty()) {
			GameServer.getInstance().getWorldManager().auctionPlayerUpdate(savePlayerMap);
		}
		//ByteBuffer out = new ByteBuffer();
		//out.writeUTF("合服准备 ->拍卖行处理成功");
		//connection.sendMsg(code, out.getBytes());
	}



	public static boolean isCanOption(GMModel gmModel, String optionType)
	{
		if (SpringContext.isDev())
			return true;

		switch (optionType) {
			case CodeFactory.GM_OPTION_ADD_PROP:
			case CodeFactory.GM_OPTION_ADD_ASSET:
			case CodeFactory.GM_OPTION_ADD_CARD:
			case CodeFactory.GM_OPTION_ADD_MONEY:
			case CodeFactory.GM_OPTION_ADD_EXP:
				return gmModel.getType() == E_GMType.SUPER.getCode() || gmModel.getType() == E_GMType.ADMIN.getCode();
			case CodeFactory.GM_OPTION_INVINCIBLE:
			case CodeFactory.GM_OPTION_JUMP_GUIDE:
			case CodeFactory.GM_OPTION_OTHER:
			case CodeFactory.GM_OPTION_OFFLINE:
			case CodeFactory.GM_OPTION_FORBID:
				return gmModel.getType() == E_GMType.SUPER.getCode();
			default:
				return true;
		}
	}

	public static boolean isCanOption(GMModel gmModel, int code)
	{
		if (SpringContext.isDev())
			return true;

		switch (code) {
			case CodeFactory.GM_ACCOUNT_ADD:
			case CodeFactory.GM_SYSTEM_SERVER_CONFIG:
			case CodeFactory.GM_PLAYER_CLEAR:
			case CodeFactory.GM_SYSTEM_SUPER_CMD:
				return gmModel.getType() == E_GMType.SUPER.getCode();

			case CodeFactory.GM_SYSTEM_OBJECT_CONFIG:
			case CodeFactory.GM_SYSTEM_OTHER_CONFIG:
//			case CodeFactory.GM_SYSTEM_CREATE_ROBOT:
			case CodeFactory.GM_SYSTEM_NOTICE_SEND:
			case CodeFactory.GM_PLAYER_MAIL_SEND:
			case CodeFactory.GM_PLAYER_RECHARGE:
			case CodeFactory.GM_PLAYER_OPTION:
			case CodeFactory.GM_PLAYER_EXPORT:
				return gmModel.getType() == E_GMType.SUPER.getCode() || gmModel.getType() == E_GMType.ADMIN.getCode();

			default:
				return true;
		}
	}


}
